 /*******************************************************************************
  * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.ui.internal.decorators;

 import java.util.ArrayList ;
 import java.util.Collection ;
 import java.util.HashSet ;
 import java.util.Iterator ;
 import java.util.Set ;
 import java.util.StringTokenizer ;

 import org.eclipse.core.runtime.IConfigurationElement;
 import org.eclipse.core.runtime.IExtension;
 import org.eclipse.core.runtime.IExtensionPoint;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.ListenerList;
 import org.eclipse.core.runtime.Platform;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker;
 import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
 import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
 import org.eclipse.jface.util.SafeRunnable;
 import org.eclipse.jface.viewers.DecorationContext;
 import org.eclipse.jface.viewers.IBaseLabelProvider;
 import org.eclipse.jface.viewers.IColorDecorator;
 import org.eclipse.jface.viewers.IDecorationContext;
 import org.eclipse.jface.viewers.IDelayedLabelDecorator;
 import org.eclipse.jface.viewers.IFontDecorator;
 import org.eclipse.jface.viewers.ILabelDecorator;
 import org.eclipse.jface.viewers.ILabelProviderListener;
 import org.eclipse.jface.viewers.ILightweightLabelDecorator;
 import org.eclipse.jface.viewers.LabelDecorator;
 import org.eclipse.jface.viewers.LabelProviderChangedEvent;
 import org.eclipse.swt.graphics.Color;
 import org.eclipse.swt.graphics.Font;
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.ui.IDecoratorManager;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.internal.IPreferenceConstants;
 import org.eclipse.ui.internal.LegacyResourceSupport;
 import org.eclipse.ui.internal.Workbench;
 import org.eclipse.ui.internal.WorkbenchMessages;
 import org.eclipse.ui.internal.WorkbenchPlugin;
 import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
 import org.eclipse.ui.internal.util.PrefUtil;
 import org.eclipse.ui.internal.util.Util;
 import org.eclipse.ui.progress.WorkbenchJob;

 /**
  * The DecoratorManager is the class that handles all of the
  * decorators defined in the image.
  *
  * @since 2.0
  */
 public class DecoratorManager extends LabelDecorator implements IDelayedLabelDecorator,
         ILabelProviderListener, IDecoratorManager, IFontDecorator, IColorDecorator, IExtensionChangeHandler {

     private static String EXTENSIONPOINT_UNIQUE_ID = WorkbenchPlugin.PI_WORKBENCH + "." + IWorkbenchRegistryConstants.PL_DECORATORS; //$NON-NLS-1$

     /**
      * The family for the decorate job.
      */
     public static final Object FAMILY_DECORATE = new Object ();

     private DecorationScheduler scheduler;

     private LightweightDecoratorManager lightweightManager;

     //Hold onto the list of listeners to be told if a change has occured
 private ListenerList listeners = new ListenerList();

     //The full definitions read from the registry.
 //Initalize to an empty collection as this is rarely used now.
 private FullDecoratorDefinition[] fullDefinitions;

     private FullTextDecoratorRunnable fullTextRunnable = new FullTextDecoratorRunnable();

     private FullImageDecoratorRunnable fullImageRunnable = new FullImageDecoratorRunnable();

     private static final FullDecoratorDefinition[] EMPTY_FULL_DEF = new FullDecoratorDefinition[0];

     private final String PREFERENCE_SEPARATOR = ","; //$NON-NLS-1$

     private final String VALUE_SEPARATOR = ":"; //$NON-NLS-1$

     private final String P_TRUE = "true"; //$NON-NLS-1$

     private final String P_FALSE = "false"; //$NON-NLS-1$

     /**
      * Create a new instance of the receiver and load the
      * settings from the installed plug-ins.
      */
     public DecoratorManager() {
         
         scheduler = new DecorationScheduler(this);
         IExtensionTracker tracker = PlatformUI.getWorkbench()
                 .getExtensionTracker();
         tracker.registerHandler(this, ExtensionTracker.createExtensionPointFilter(getExtensionPointFilter()));
     }

     /**
      * Initalize the decorator definitions.
      */
     private void initializeDecoratorDefinitions() {
         DecoratorRegistryReader reader = new DecoratorRegistryReader();
         Collection values = reader
                 .readRegistry(Platform.getExtensionRegistry());

         ArrayList full = new ArrayList ();
         ArrayList lightweight = new ArrayList ();
         Iterator allDefinitions = values.iterator();
         IExtensionTracker configurationElementTracker = PlatformUI
                 .getWorkbench().getExtensionTracker();
         while (allDefinitions.hasNext()) {
             DecoratorDefinition nextDefinition = (DecoratorDefinition) allDefinitions
                     .next();
             if (nextDefinition.isFull()) {
                 full.add(nextDefinition);
             } else {
                 lightweight.add(nextDefinition);
             }
                         
             configurationElementTracker.registerObject(nextDefinition.getConfigurationElement().getDeclaringExtension(), nextDefinition, IExtensionTracker.REF_WEAK);
         }

         fullDefinitions = new FullDecoratorDefinition[full.size()];
         full.toArray(fullDefinitions);

         LightweightDecoratorDefinition[] lightweightDefinitions = new LightweightDecoratorDefinition[lightweight
                 .size()];
         lightweight.toArray(lightweightDefinitions);

         lightweightManager = new LightweightDecoratorManager(
                 lightweightDefinitions);
         
         applyDecoratorsPreference();
     }

     /**
      * For dynamic UI
      *
      * @param definition the definition to add
      * @since 3.0
      */
     public void addDecorator(DecoratorDefinition definition) {
         if (definition.isFull()) {
             if (getFullDecoratorDefinition(definition.getId()) == null) {
                 FullDecoratorDefinition[] oldDefs = getFullDefinitions();
                 fullDefinitions = new FullDecoratorDefinition[fullDefinitions.length + 1];
                 System
                         .arraycopy(oldDefs, 0, fullDefinitions, 0,
                                 oldDefs.length);
                 fullDefinitions[oldDefs.length] = (FullDecoratorDefinition) definition;
                 clearCaches();
                 updateForEnablementChange();
             }
         } else {
             if (getLightweightManager().addDecorator(
                     (LightweightDecoratorDefinition) definition)) {
                 clearCaches();
                 updateForEnablementChange();
             }
         }
         ((Workbench) PlatformUI.getWorkbench())
                 .getExtensionTracker().registerObject(
                         definition.getConfigurationElement().getDeclaringExtension(), definition, IExtensionTracker.REF_WEAK);
     }

     /**
      * See if the supplied decorator cache has a value for the
      * element. If not calculate it from the enabledDefinitions and
      * update the cache.
      * @return Collection of DecoratorDefinition.
      * @param element The element being tested.
      * @param enabledDefinitions The definitions currently defined for this decorator.
      */
     static Collection getDecoratorsFor(Object element,
             DecoratorDefinition[] enabledDefinitions) {

         ArrayList decorators = new ArrayList ();

         for (int i = 0; i < enabledDefinitions.length; i++) {
             if (enabledDefinitions[i].isEnabledFor(element)) {
                 decorators.add(enabledDefinitions[i]);
             }
         }

         return decorators;

     }


     /**
      * Add the listener to the list of listeners.
      */
     public void addListener(ILabelProviderListener listener) {
         listeners.add(listener);
     }

     /**
      * Remove the listener from the list.
      */
     public void removeListener(ILabelProviderListener listener) {
         listeners.remove(listener);
         scheduler.listenerRemoved(listener);
     }
     
     /**
      * Get the list of elements listening to the receiver.
      * @return ILabelProviderListener []
      */
     ILabelProviderListener [] getListeners(){
         Object [] array = listeners.getListeners();
         ILabelProviderListener [] listenerArray =
             new ILabelProviderListener [array.length];
         System.arraycopy(array,0,listenerArray,0,listenerArray.length);
         return listenerArray;
     }

     /**
      * Inform all of the listeners that require an update
      * @param listener The listener we are updating.
      * @param event
      * the event with the update details
      */
     void fireListener(final LabelProviderChangedEvent event, final ILabelProviderListener listener) {
         Platform.run(new SafeRunnable() {
             public void run() {
                 listener.labelProviderChanged(event);
             }
         });

     }
     
     /**
      * Inform all of the listeners that require an update
      * @param event the event with the update details
      */
     void fireListeners(final LabelProviderChangedEvent event) {
         Object [] array = listeners.getListeners();
         for (int i = 0; i < array.length; i++) {
             final ILabelProviderListener l = (ILabelProviderListener) array[i];
             Platform.run(new SafeRunnable() {
                 public void run() {
                     l.labelProviderChanged(event);
                 }
             });
         }
     }

     /**
      * Fire any listeners from the UIThread. Used for cases where this
      * may be invoked outside of the UI by the public API.
      * @param event the event with the update details
      */
     void fireListenersInUIThread(final LabelProviderChangedEvent event) {

         //No updates if there is no UI
 if (!PlatformUI.isWorkbenchRunning()) {
             return;
         }

         //Only bother with the job if in the UI Thread
 if (Thread.currentThread() == PlatformUI.getWorkbench().getDisplay()
                 .getThread()) {
             fireListeners(event);
             return;
         }

         WorkbenchJob updateJob = new WorkbenchJob(WorkbenchMessages.DecorationScheduler_UpdateJobName) {
             /*
              * (non-Javadoc)
              *
              * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
              */
             public IStatus runInUIThread(IProgressMonitor monitor) {
                 fireListeners(event);
                 return Status.OK_STATUS;
             }
             
             /* (non-Javadoc)
              * @see org.eclipse.core.runtime.jobs.Job#belongsTo(java.lang.Object)
              */
             public boolean belongsTo(Object family) {
                 return FAMILY_DECORATE == family;
             }
         };
         updateJob.setSystem(true);
         updateJob.schedule();

     }

     /* (non-Javadoc)
      * @see org.eclipse.jface.viewers.ILabelDecorator2#decorateText(java.lang.String, java.lang.Object, org.eclipse.jface.viewers.IDecorationContext)
      */
     public String decorateText(String text, Object element, IDecorationContext context) {
         //Get any adaptations to IResource
 Object adapted = getResourceAdapter(element);
         String result = scheduler.decorateWithText(text, element, adapted, context);
         FullDecoratorDefinition[] decorators = getDecoratorsFor(element);
         for (int i = 0; i < decorators.length; i++) {
             if (decorators[i].isEnabledFor(element)) {
                 String newResult = safeDecorateText(element, result,
                         decorators[i]);
                 if (newResult != null) {
                     result = newResult;
                 }
             }
         }

         if (adapted != null) {
             decorators = getDecoratorsFor(adapted);
             for (int i = 0; i < decorators.length; i++) {
                 if (decorators[i].isAdaptable()
                         && decorators[i].isEnabledFor(adapted)) {
                     String newResult = safeDecorateText(adapted, result,
                             decorators[i]);
                     if (newResult != null) {
                         result = newResult;
                     }
                 }
             }
         }

         return result;
     }
     
     /*
      * (non-Javadoc)
      * @see org.eclipse.jface.viewers.ILabelDecorator#decorateText(java.lang.String, java.lang.Object)
      */
     public String decorateText(String text, Object element) {
         return decorateText(text, element, DecorationContext.DEFAULT_CONTEXT);
     }

     /**
      * Decorate the text in a SafeRunnable.
      * @param element The element we are decorating
      * @param start The currently decorated String
      * @param decorator The decorator to run.
      * @param context the decoration context
      * @return String
      */
     private String safeDecorateText(Object element, String start,
             FullDecoratorDefinition decorator) {
         fullTextRunnable.setValues(start, element, decorator);
         Platform.run(fullTextRunnable);
         String newResult = fullTextRunnable.getResult();
         return newResult;
     }

     /* (non-Javadoc)
      * @see org.eclipse.jface.viewers.ILabelDecorator2#decorateImage(org.eclipse.swt.graphics.Image, java.lang.Object, org.eclipse.jface.viewers.IDecorationContext)
      */
     public Image decorateImage(Image image, Object element, IDecorationContext context) {
         Object adapted = getResourceAdapter(element);
         Image result = scheduler.decorateWithOverlays(image, element, adapted, context);
         FullDecoratorDefinition[] decorators = getDecoratorsFor(element);

         for (int i = 0; i < decorators.length; i++) {
             if (decorators[i].isEnabledFor(element)) {
                 Image newResult = safeDecorateImage(element, result,
                         decorators[i]);
                 if (newResult != null) {
                     result = newResult;
                 }
             }
         }

         //Get any adaptations to IResource

         if (adapted != null) {
             decorators = getDecoratorsFor(adapted);
             for (int i = 0; i < decorators.length; i++) {
                 if (decorators[i].isAdaptable()
                         && decorators[i].isEnabledFor(adapted)) {
                     Image newResult = safeDecorateImage(adapted, result,
                             decorators[i]);
                     if (newResult != null) {
                         result = newResult;
                     }
                 }
             }
         }

         return result;
     }

     /*
      * (non-Javadoc)
      * @see org.eclipse.jface.viewers.ILabelDecorator#decorateImage(org.eclipse.swt.graphics.Image, java.lang.Object)
      */
     public Image decorateImage(Image image, Object element) {
         return decorateImage(image, element, DecorationContext.DEFAULT_CONTEXT);
     }

     /**
      * Decorate the image in a SafeRunnable.
      * @param element The element we are decorating
      * @param start The currently decorated Image
      * @param decorator The decorator to run.
      * @param context The decoration context
      * @return Image
      */
     private Image safeDecorateImage(Object element, Image start,
             FullDecoratorDefinition decorator) {
         fullImageRunnable.setValues(start, element, decorator);
         Platform.run(fullImageRunnable);
         Image newResult = fullImageRunnable.getResult();
         return newResult;
     }

     /**
      * Get the resource adapted object for the supplied
      * element. Return <code>null</code>. if there isn't one.
      * @param element
      * @return Object or <code>null</code>.
      */
     private Object getResourceAdapter(Object element) {
         Object adapted = LegacyResourceSupport.getAdaptedContributorResource(element);
         if (adapted != element) {
             return adapted; //Avoid applying decorator twice
 }
         return null;
     }

     /**
      * Return whether or not the decorator registered for element
      * has a label property called property name.
      */
     public boolean isLabelProperty(Object element, String property) {
         return isLabelProperty(element, property, true);
     }

     /**
      * Return whether or not the decorator registered for element
      * has a label property called property name.
      * Check for an adapted resource if checkAdapted is true.
      * @param element
      * @param property
      * @param checkAdapted
      * @return boolean <code>true</code> if there is a label property
      * for element or its adapted value
      */
     public boolean isLabelProperty(Object element, String property,
             boolean checkAdapted) {
         boolean fullCheck = isLabelProperty(element, property,
                 getDecoratorsFor(element));

         if (fullCheck) {
             return fullCheck;
         }

         boolean lightweightCheck = isLabelProperty(element, property,
                 getLightweightManager().getDecoratorsFor(element));

         if (lightweightCheck) {
             return true;
         }

         if (checkAdapted) {
             //Get any adaptions to IResource
 Object adapted = getResourceAdapter(element);
             if (adapted == null || adapted == element) {
                 return false;
             }

             fullCheck = isLabelProperty(adapted, property,
                     getDecoratorsFor(adapted));
             if (fullCheck) {
                 return fullCheck;
             }

             return isLabelProperty(adapted, property, lightweightManager
                     .getDecoratorsFor(adapted));
         }
         return false;
     }

     private boolean isLabelProperty(Object element, String property,
             DecoratorDefinition[] decorators) {
         for (int i = 0; i < decorators.length; i++) {
             if (decorators[i].isEnabledFor(element)
                     && decorators[i].isLabelProperty(element, property)) {
                 return true;
             }
         }

         return false;
     }

     /**
      * Return the enabled full decorator definitions.
      * @return FullDecoratorDefinition[]
      */
     private FullDecoratorDefinition[] enabledFullDefinitions() {
       
         FullDecoratorDefinition[] full = getFullDefinitions();
         //As this are a deprecated data type optimize for
 //the undefined case.
 if(full.length == 0) {
             return full;
         }
         ArrayList result = new ArrayList ();
         for (int i = 0; i < full.length; i++) {
             if (full[i].isEnabled()) {
                 result.add(full[i]);
             }
         }
         FullDecoratorDefinition[] returnArray = new FullDecoratorDefinition[result
                 .size()];
         result.toArray(returnArray);
         return returnArray;
     }

     /*
      * @see IBaseLabelProvider#dispose()
      */
     public void dispose() {
        //do nothing
 }

     /**
      * Clear the caches in the manager. This is required
      * to avoid updates that may occur due to changes in
      * enablement.
      */
     public void clearCaches() {
         getLightweightManager().reset();
         fullTextRunnable.clearReferences();
         fullImageRunnable.clearReferences();
     }

     /**
      * Enablement had changed. Fire the listeners and write
      * the preference.
      */
     public void updateForEnablementChange() {
         //Clear any results that may be around as all labels have changed
 scheduler.clearResults();
         fireListenersInUIThread(new LabelProviderChangedEvent(this));
         writeDecoratorsPreference();
     }

     /**
      * Get the DecoratorDefinitions defined on the receiver.
      * @return DecoratorDefinition[]
      */
     public DecoratorDefinition[] getAllDecoratorDefinitions() {
         LightweightDecoratorDefinition[] lightweightDefinitions = getLightweightManager()
                 .getDefinitions();
         DecoratorDefinition[] returnValue = new DecoratorDefinition[fullDefinitions.length
                 + lightweightDefinitions.length];
         System.arraycopy(fullDefinitions, 0, returnValue, 0,
                 fullDefinitions.length);
         System.arraycopy(lightweightDefinitions, 0, returnValue,
                 fullDefinitions.length, lightweightDefinitions.length);
         return returnValue;
     }

     /*
      * @see ILabelProviderListener#labelProviderChanged(LabelProviderChangedEvent)
      */
     public void labelProviderChanged(LabelProviderChangedEvent event) {
         Object [] elements = event.getElements();
         scheduler.clearResults();
         //If the elements are not specified send out a general update
 if (elements == null) {
             fireListeners(event);
         } else {
             //Assume that someone is going to care about the
 //decoration result and just start it right away
 for (int i = 0; i < elements.length; i++) {
                 Object adapted = getResourceAdapter(elements[i]);
                 //Force an update in case full decorators are the only ones enabled
 scheduler.queueForDecoration(elements[i], adapted, true, null, DecorationContext.DEFAULT_CONTEXT);
             }
         }
     }

     /**
      * Store the currently enabled decorators in
      * preference store.
      */
     private void writeDecoratorsPreference() {
         StringBuffer enabledIds = new StringBuffer ();
         writeDecoratorsPreference(enabledIds, getFullDefinitions());
         writeDecoratorsPreference(enabledIds, getLightweightManager()
                 .getDefinitions());

         WorkbenchPlugin.getDefault().getPreferenceStore().setValue(
                 IPreferenceConstants.ENABLED_DECORATORS, enabledIds.toString());
         PrefUtil.savePrefs();
     }

     private void writeDecoratorsPreference(StringBuffer enabledIds,
             DecoratorDefinition[] definitions) {
         for (int i = 0; i < definitions.length; i++) {
             enabledIds.append(definitions[i].getId());
             enabledIds.append(VALUE_SEPARATOR);
             if (definitions[i].isEnabled()) {
                 enabledIds.append(P_TRUE);
             } else {
                 enabledIds.append(P_FALSE);
             }

             enabledIds.append(PREFERENCE_SEPARATOR);
         }
     }

     /**
      * Get the currently enabled decorators in
      * preference store and set the state of the
      * current definitions accordingly.
      */
     public void applyDecoratorsPreference() {

         String preferenceValue = WorkbenchPlugin.getDefault()
                 .getPreferenceStore().getString(
                         IPreferenceConstants.ENABLED_DECORATORS);

         StringTokenizer tokenizer = new StringTokenizer (preferenceValue,
                 PREFERENCE_SEPARATOR);
         Set enabledIds = new HashSet ();
         Set disabledIds = new HashSet ();
         while (tokenizer.hasMoreTokens()) {
             String nextValuePair = tokenizer.nextToken();

             //Strip out the true or false to get the id
 String id = nextValuePair.substring(0, nextValuePair
                     .indexOf(VALUE_SEPARATOR));
             if (nextValuePair.endsWith(P_TRUE)) {
                 enabledIds.add(id);
             } else {
                 disabledIds.add(id);
             }
         }

         FullDecoratorDefinition[] full = getFullDefinitions();
         for (int i = 0; i < full.length; i++) {
             String id = full[i].getId();
             if (enabledIds.contains(id)) {
                 full[i].setEnabled(true);
             } else {
                 if (disabledIds.contains(id)) {
                     full[i].setEnabled(false);
                 }
             }
         }

         LightweightDecoratorDefinition[] lightweightDefinitions = getLightweightManager()
                 .getDefinitions();
         for (int i = 0; i < lightweightDefinitions.length; i++) {
             String id = lightweightDefinitions[i].getId();
             if (enabledIds.contains(id)) {
                 lightweightDefinitions[i].setEnabled(true);
             } else {
                 if (disabledIds.contains(id)) {
                     lightweightDefinitions[i].setEnabled(false);
                 }
             }
         }

     }

     /**
      * Shutdown the decorator manager by disabling all
      * of the decorators so that dispose() will be called
      * on them.
      */
     public void shutdown() {
         //Disable all of the enabled decorators
 //so as to force a dispose of thier decorators
 FullDecoratorDefinition[] full = getFullDefinitions();
         for (int i = 0; i < full.length; i++) {
             if (full[i].isEnabled()) {
                 full[i].setEnabled(false);
             }
         }
         if(lightweightManager != null) {
             getLightweightManager().shutdown();
         }
         scheduler.shutdown();
         dispose();
     }

     
     /* (non-Javadoc)
      * @see org.eclipse.ui.IDecoratorManager#getEnabled(java.lang.String)
      */
     public boolean getEnabled(String decoratorId) {
         DecoratorDefinition definition = getDecoratorDefinition(decoratorId);
         if (definition == null) {
             return false;
         }
         return definition.isEnabled();
     }

     /**
      * @see IDecoratorManager#getLabelDecorator()
      */
     public ILabelDecorator getLabelDecorator() {
         return this;
     }

     /**
      * @see IDecoratorManager#setEnabled(String, boolean)
      */
     public void setEnabled(String decoratorId, boolean enabled) {
         DecoratorDefinition definition = getDecoratorDefinition(decoratorId);
         if (definition != null) {
             definition.setEnabled(enabled);
             clearCaches();
             updateForEnablementChange();
         }
     }

     /*
      * @see IDecoratorManager#getBaseLabelProvider(String)
      */
     public IBaseLabelProvider getBaseLabelProvider(String decoratorId) {
         IBaseLabelProvider fullProvider = getLabelDecorator(decoratorId);
         if (fullProvider == null) {
             return getLightweightLabelDecorator(decoratorId);
         }
         return fullProvider;
     }

     /*
      * @see IDecoratorManager#getLabelDecorator(String)
      */
     public ILabelDecorator getLabelDecorator(String decoratorId) {
         FullDecoratorDefinition definition = getFullDecoratorDefinition(decoratorId);

         //Do not return for a disabled decorator
 if (definition != null && definition.isEnabled()) {
             return definition.getDecorator();
         }
         return null;
     }

     /*
      * @see IDecoratorManager#getLightweightLabelDecorator(String)
      */
     public ILightweightLabelDecorator getLightweightLabelDecorator(
             String decoratorId) {
         LightweightDecoratorDefinition definition = getLightweightManager()
                 .getDecoratorDefinition(decoratorId);
         //Do not return for a disabled decorator
 if (definition != null && definition.isEnabled()) {
             return definition.getDecorator();
         }
         return null;
     }

     /**
      * Get the DecoratorDefinition with the supplied id
      * @return DecoratorDefinition or <code>null</code> if it is not found
      * @param decoratorId String
      */
     private DecoratorDefinition getDecoratorDefinition(String decoratorId) {
         DecoratorDefinition returnValue = getFullDecoratorDefinition(decoratorId);
         if (returnValue == null) {
             return getLightweightManager().getDecoratorDefinition(decoratorId);
         }
         return returnValue;
     }

     /**
      * Get the FullDecoratorDefinition with the supplied id
      * @return FullDecoratorDefinition or <code>null</code> if it is not found
      * @param decoratorId the id
      */
     private FullDecoratorDefinition getFullDecoratorDefinition(
             String decoratorId) {
         int idx = getFullDecoratorDefinitionIdx(decoratorId);
         if (idx != -1) {
             return getFullDefinitions()[idx];
         }
         return null;
     }
     
     /**
      * Return the index of the definition in the array.
      *
      * @param decoratorId the id
      * @return the index of the definition in the array or <code>-1</code>
      * @since 3.1
      */
     private int getFullDecoratorDefinitionIdx(
             String decoratorId) {
         FullDecoratorDefinition[] full = getFullDefinitions();
         for (int i = 0; i < full.length; i++) {
             if (full[i].getId().equals(decoratorId)) {
                 return i;
             }
         }
         return -1;
     }
             

     /**
      * Get the full decorator definitions registered for elements of this type.
      * @param element The element to look up
      * @return FullDecoratorDefinition[]
      */
     private FullDecoratorDefinition[] getDecoratorsFor(Object element) {

         if (element == null) {
             return EMPTY_FULL_DEF;
         }

           Collection decorators = getDecoratorsFor(element,
                 enabledFullDefinitions());
         FullDecoratorDefinition[] decoratorArray = EMPTY_FULL_DEF;
         if (decorators.size() > 0){
             decoratorArray = new FullDecoratorDefinition[decorators.size()];
             decorators.toArray(decoratorArray);
         }

         return decoratorArray;
     }

     /**
      * Returns the lightweightManager. This method is
      * public for use by test cases. No other classes outside of
      * this package should use this method.
      * @return LightweightDecoratorManager
      */
     public LightweightDecoratorManager getLightweightManager() {
         if(lightweightManager == null) {
             initializeDecoratorDefinitions();
         }
         return lightweightManager;
     }

     /**
      * @see org.eclipse.ui.IDecoratorManager#update(java.lang.String)
      */
     public void update(String decoratorId) {

         IBaseLabelProvider provider = getBaseLabelProvider(decoratorId);
         if (provider != null) {
             scheduler.clearResults();
             fireListeners(new LabelProviderChangedEvent(provider));
         }

     }
     
     public boolean prepareDecoration(Object element, String originalText, IDecorationContext context) {
         // Check if there is a decoration ready or if there is no lightweight decorators to be applied
 if (scheduler.isDecorationReady(element, context)
                 || !getLightweightManager().hasEnabledDefinitions()) {
             return true;
         }

         // Force an update if there is a text already
 boolean force = true;
         //If not then do not force as the undecorated value is fine
 if(originalText == null || originalText.length() == 0) {
             force = false;
         }
         
         // Queue the decoration.
 scheduler.queueForDecoration(element, getResourceAdapter(element),
                 force, originalText, context);

         //If all that is there is deferred ones then defer decoration.
 //For the sake of efficiency we do not test for enablement at this
 //point and just abandon deferment if there are any to run right
 //away
 return getFullDefinitions().length > 0;
     }

     /* (non-Javadoc)
      * @see org.eclipse.jface.viewers.IDelayedLabelDecorator#prepareDecoration(java.lang.Object, java.lang.String)
      */
     public boolean prepareDecoration(Object element, String originalText) {
         return prepareDecoration(element, originalText, DecorationContext.DEFAULT_CONTEXT);
     }
     
     /* (non-Javadoc)
      * @see org.eclipse.jface.viewers.IFontDecorator#decorateFont(java.lang.Object)
      */
     public Font decorateFont(Object element) {
         return scheduler.getFont(element, getResourceAdapter(element));
     }
     /* (non-Javadoc)
      * @see org.eclipse.jface.viewers.IColorDecorator#decorateBackground(java.lang.Object)
      */
     public Color decorateBackground(Object element) {
         return scheduler.getBackgroundColor(element, getResourceAdapter(element));
     }
     /* (non-Javadoc)
      * @see org.eclipse.jface.viewers.IColorDecorator#decorateForeground(java.lang.Object)
      */
     public Color decorateForeground(Object element) {
         return scheduler.getForegroundColor(element, getResourceAdapter(element));
     }
     /**
      * Get all of the defined fullDefinitions. Initalize if
      * required
      * @return FullDecoratorDefinition[]
      */
     private FullDecoratorDefinition[] getFullDefinitions() {
         if(fullDefinitions == null) {
             initializeDecoratorDefinitions();
         }
         return fullDefinitions;
     }

     private IExtensionPoint getExtensionPointFilter() {
         return Platform.getExtensionRegistry().getExtensionPoint(EXTENSIONPOINT_UNIQUE_ID);
     }

     /* (non-Javadoc)
      * @see org.eclipse.core.runtime.dynamicHelpers.IExtensionChangeHandler#addExtension(org.eclipse.core.runtime.dynamicHelpers.IExtensionTracker, org.eclipse.core.runtime.IExtension)
      */
     public void addExtension(IExtensionTracker tracker, IExtension addedExtension) {
         IConfigurationElement addedElements[] = addedExtension.getConfigurationElements();
         for (int i = 0; i < addedElements.length; i++) {
             DecoratorRegistryReader reader = new DecoratorRegistryReader();
             reader.readElement(addedElements[i]);
             for (Iterator j = reader.getValues().iterator(); j.hasNext();) {
                 addDecorator((DecoratorDefinition) j.next());
             }
         }
     }

     /* (non-Javadoc)
      * @see org.eclipse.core.runtime.dynamicHelpers.IExtensionChangeHandler#removeExtension(org.eclipse.core.runtime.IExtension, java.lang.Object[])
      */
     public void removeExtension(IExtension source, Object [] objects) {
         
         boolean shouldClear = false;
         for (int i = 0; i < objects.length; i++) {
             if (objects[i] instanceof DecoratorDefinition) {
                 DecoratorDefinition definition = (DecoratorDefinition) objects[i];
                 if (definition.isFull()) {
                     int idx = getFullDecoratorDefinitionIdx(definition.getId());
                     if (idx != -1) {
                         FullDecoratorDefinition[] oldDefs = getFullDefinitions();
                         Util
                                 .arrayCopyWithRemoval(
                                         oldDefs,
                                         fullDefinitions = new FullDecoratorDefinition[fullDefinitions.length - 1],
                                         idx);
                         shouldClear = true;
                     }
                 } else {
                     shouldClear |= getLightweightManager().removeDecorator(
                             (LightweightDecoratorDefinition) definition);
                 }
             }
         }
         
         if(shouldClear){
               clearCaches();
               updateForEnablementChange();
         }
         
     }

 }

